<?php

abstract class Model_Abstract
{

    /**
     * 数据表对象
     * @var Zend_Db_Table_Abstract
     */
    protected $_table;
    /**
     * 对象数据
     * @var Array
     */
    protected $_data;
    /**
     * 对象主键
     */
    protected $_primaryKey;

	/**
     * 构造方法
     *
     * 初始化一个对象
     *
     * @param array $options 对象数据
     * @return void
     */
    public function __construct($options = null)
    {
        if (is_array($options)) {
            $this->setData($options);
        }elseif(is_int($options)){
            $obj = $this->find($options);
            if($obj){
                $this->_data = $obj->toArray();
            }
        }
    }

    /**
     * __set() 设置对象的一个属性值
     *
     * @param string $name
     * @param mixed  $value
     */
    public function __set($name, $value)
    {
        $this->_data[$name] = $value;
    }

    /**
     * __get() 返回对象的一个属性值
     *
     * @param  string $name
     * @return mixed
     */
    public function __get($name)
    {
        if(isset($this->_data[$name])){
            return $this->_data[$name];
        }
        trigger_error('属性 ' . $name . '" 不存在', E_USER_NOTICE);
        return NULL;
    }

    /**
     * 魔术方法，用来设置或返回用户的属性
     * 如getRealname(),setRealname('卢于静')
     */
    public function __call($method, $args)
    {
        $property = strtolower(substr($method,3));
        if(substr($method,0,3) == 'set'){
            if(isset($this->_data[$property])&&is_scalar($args)){
                $this->_data[$property] = $args;
                return ;
            }elseif (is_array($args)){
                return $this->setData($args);
            }
        }elseif(substr($method,0,3) == 'get'){
            if(isset($this->_data[$property])){
                return $this->_data[$property];
            }
            return ;
        }
        throw new Exception('方法调用错误，不存在'.$method.'这个方法！');
    }

    /**
     * 用数据填充一个对象
     *
     * @param array $data 对象信息
     * @return Object
     */
    public function setData(array $data)
    {
        if (is_array($data)) {
            $this->_data = array_merge((array)$this->_data,$data);
        }
        return $this;
    }

    /**
     * 获取对象的信息
     *
     * @param string $name
     * @return mixed
     */
    public function getData($name = null)
    {
        if($name === null){
            return $this->_data;
        }elseif (is_string($name)&&isset($this->_data[$name])){
            return $this->_data[$name];
        }
        return NULL;
    }

	/**
     * 设置对象表
     *
     * @param mixed $dbTable
     * @return Model_Abstract
     */
    public function setTable($dbTable)
    {
        if (is_string($dbTable)) {
            $dbTable = new $dbTable();
        }
        if (!$dbTable instanceof Zend_Db_Table_Abstract) {
            throw new Exception('Invalid table data gateway provided');
        }
        $this->_table = $dbTable;
        return $this;
    }

    /**
     * 获取对象表
     *
     * @return Zend_Db_Table
     */
    public function getTable()
    {
        if(null === $this->_table){
            $name = ucfirst(array_pop(explode('_',get_class($this))));
            $this->setTable('Model_DbTable_'.$name);
        }
        return $this->_table;
    }

    /**
     * 根据ID获取一个对象
     *
     * @param int $id
     * @return Model_Abstract
     */
    public function find($id)
    {
        $result = $this->getTable()->find($id);
        if (0 == count($result)) {
            return;
        }
        $obj = $result->current();
        $this->_data = $obj->toArray();
        return $this;
    }

    /**
     * 获取所有对象,与zend_paginator配合使用
     *
	 * @param  array $where  形式为(fieldName,  and/Or, compare, value)
     * @param  array $order  形式为(fieldName, order)
     * @return  mixed $select
     */
    public function fetchAll(Array $where = array(), Array $order = array())
    {
        $select = $this->getTable()->select();
        foreach ($where AS $w){
	        if ($w[1] == 'or') {
	        	$select->orWhere($w[0] . $w[2] . "?", $w[3]);
	        } else {
	            $select->where($w[0] . $w[2] . "?", $w[3]);
	        }
	    }
	    if(empty($order)){
	        $order = array(array($this->getPrimaryKey(),'DESC'));
	    }
	    foreach ($order as $o) {
	    	$select->order($o[0] . " " . $o[1]);
	    }
	    return $select;
    }

    /**
     * 获取所有对象
     *
	 * @param  array $where  形式为(fieldName,  and/Or, compare, value)
     * @param  array $order  形式为(fieldName, order)
     * @return  mixed
     */
    public function dataList(Array $where = array(), Array $order = array())
    {
        $select = $this->getTable()->select();
        foreach ($where AS $w){
	        if ($w[1] == 'or') {
	        	$select->orWhere($w[0] . $w[2] . "?", $w[3]);
	        } else {
	            $select->where($w[0] . $w[2] . "?", $w[3]);
	        }
	    }
	    if(empty($order)){
	        $order = array(array($this->getPrimaryKey(),'DESC'));
	    }
	    foreach ($order as $o) {
	    	$select->order($o[0] . " " . $o[1]);
	    }
	    return $this->getTable()->fetchAll($select);
    }

    /**
     * 保存或更新对象
     *
     * @param $data
     * @return Int
     */
    public function save(array $data = array())
    {
        $msg = $this->preSave();
        if(true !== $msg){
            throw new Exception($msg);
        }
        $primary = $this->getPrimaryKey();
        $primaryValue = $this->getData($primary);
        if(!empty($data)){
            $this->setData($data);
        }
        $fields = $this->getTable()->info(Zend_Db_Table_Abstract::COLS);
        foreach ($this->_data as $field => $value) {
            if (!in_array($field, $fields)) {
                unset($this->_data[$field]);
            }
        }
        $_data = $this->_data;
        if(null === $primaryValue){
            return $this->getTable()->insert($_data);
        }else{
            unset($_data[$primary]);
            return $this->getTable()->update($_data,array($primary.'=?'=>$primaryValue));
        }
    }

    /**
     * 对象持久化以前预处理数据
     * 在这里可以进行数据验证，或添加一些信息到对象中
     *
     * @return Bool|String
     */
    public function preSave()
    {
        return true;
    }

    /**
     * 删除当前对象，包括数据库中
     */
    public function drop()
    {
        $primaryKey = $this->getPrimaryKey();
        $primaryValue = $this->getData($primaryKey);
        $where = array($primaryKey . '=?'=>$primaryValue);
        $this->_data = null;
        return $this->getTable()->delete($where);
    }

    /**
     * 获取表的第一个主键
     *
     * @return String
     */
    public function getPrimaryKey()
    {
        if(NULL === $this->_primaryKey){
            $this->_primaryKey = current($this->getTable()->info('primary'));
        }
        return $this->_primaryKey;
    }

    /**
     * 将对象转换为数组
     *
     * @return Array
     */
    public function toArray()
    {
        return (array)$this->_data;
    }

}